package safety

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/bobo-rs/innovideo-services/consts"
	"gitee.com/bobo-rs/innovideo-services/enums"
	"gitee.com/bobo-rs/innovideo-services/library/models"
	"log"
	"time"
)

// GetSign 获取安全密钥签名
func (s *sSafety) GetSign(ctx context.Context, tag enums.SafeTags) (*models.SafeSignItem, error) {
	// 并发限制
	var (
		item = &models.SafeSignItem{
			Secret: s.Secret(tag), // 获取密钥-适用于用户端入参敏感数据加密，例如手机号、身份证等
		}
		secret = s.Secret(tag) // 生成签名密钥-缓存到服务端，用于加解密签名-不对外
	)

	// 验证规则
	err := s.Validate(ctx, tag)
	if err != nil {
		return nil, err
	}

	// 签名参数转JSON
	buffer, err := json.Marshal(models.SignItem{
		Secret:    item.Secret,
		Timestamp: time.Now().Add(time.Minute * 10).Unix(), // 十分钟
		Nonce:     s.Shuffle(),
	})
	if err != nil {
		return nil, fmt.Errorf(`生成签名转换Json失败，请重试，%s`, err.Error())
	}

	// 生成签名
	item.Sign, err = s.AESHandler(secret).EncryptString(buffer)
	if err != nil {
		return nil, fmt.Errorf(`生成签名失败，%s`, err.Error())
	}

	// 设置Tag密钥缓存
	err = s.SetTagCache(ctx, tag, secret)
	return item, err
}

// Verify 验证签名并解密签名值
func (s *sSafety) Verify(ctx context.Context, sign string, tag enums.SafeTags, isRemove ...bool) (*models.SignItem, error) {
	// 获取加密密钥
	secret, err := s.GetSecretTagMac(ctx, tag)
	if err != nil {
		return nil, err
	}

	// 签名解密
	buff, err := s.Decrypt(sign, *secret)
	if err != nil {
		return nil, fmt.Errorf(`签名验证失败，%s`, err.Error())
	}

	// 转换为JSON
	decoder := s.ToJson(buff)

	// 解析JSON，是否JSON字串
	if decoder.More() == false {
		return nil, errors.New(`签名验证不通过`)
	}

	// 转换签名数据
	item := &models.SignItem{}
	if err = decoder.Decode(&item); err != nil {
		return nil, err
	}

	// 验证是否过期
	if item.Timestamp < time.Now().Unix() {
		return nil, errors.New(`签名已过期，请重试`)
	}

	// 移除密钥，只能验证一次，验证之后即销毁
	if len(isRemove) > 0 && isRemove[0] == true {
		_ = s.RemoveSecretTagMac(ctx, tag)
	}
	return item, nil
}

// SetTagCache 设置安全密钥Tag缓存处理
func (s *sSafety) SetTagCache(ctx context.Context, tag enums.SafeTags, secret string) error {
	// 设置密钥
	err := s.SetSecretTagMac(ctx, tag, secret)
	if err != nil {
		return err
	}
	// 记录用户1分钟tag刷新数量
	err = s.SetSecret1MinuteTagMacRefreshNum(ctx, tag)
	// 记录用户1小时tag刷新数量
	err = s.SetSecret1HourTagMacRefreshNum(ctx, tag)
	// 记录1分钟刷新Tag量
	err = s.SetSecret1MinuteTagRefreshNum(ctx, tag)
	// 记录24小时刷新数量
	err = s.SetSecret24HourTagRefreshNum(ctx, tag)
	if err != nil {
		log.Println(`设置缓存刷新数量报错`, err)
	}
	return nil
}

// Validate 验证安全密钥生成规则
func (s *sSafety) Validate(ctx context.Context, tag enums.SafeTags) error {
	// 验证用户同一个Tag一分钟刷新次数
	num, err := s.GetSecret1MinuteTagMacRefreshNum(ctx, tag)
	if err != nil {
		return err
	}
	// 验证规则
	if consts.SafeSecret1MinuteRefreshLimitNumTagMac <= num {
		return fmt.Errorf(`同一个Tag[%s]签名一分钟内刷新次数超过限制%d，稍后再试`, tag, num)
	}
	// 验证用户同一个Tag一小时刷新次数
	num, err = s.GetSecret1HourTagMacRefreshNum(ctx, tag)
	if err != nil {
		return err
	}
	if consts.SafeSecret1HourRefreshLimitNumTagMac <= num {
		return fmt.Errorf(`同一个Tag[%s]签名一小时内刷新次数超过限制%d，稍后再试`, tag, num)
	}

	// 同一个Tag一分钟刷新次数
	num, err = s.GetSecret1MinuteTagRefreshNum(ctx, tag)
	if err != nil {
		return err
	}
	if consts.SafeSecret1MinuteRefreshLimitNumTag <= num {
		return fmt.Errorf(`当前Tag[%s]服务签名一分钟内刷新次数超过限制%d，稍后再试`, tag, num)
	}

	// 同一个Tag24小时刷新次数
	num, err = s.GetSecret24HourTagRefreshNum(ctx, tag)
	if err != nil {
		return err
	}
	if consts.SafeSecret24HourRefreshLimitNumTag <= num {
		return fmt.Errorf(`当前Tag[%s]服务签名24小时内刷新次数超过限制%d，稍后再试`, tag, num)
	}
	return nil
}
